package queue;

/**
 * 用数组模拟队列
 * 先进先出
 */
public class ArrayQueueDemo {
    public static void main(String[] args) {
        ArrayQueue arrayQueue = new ArrayQueue(3);
        System.out.println(2%3);
    }
}

class ArrayQueue {
    int maxSize;
    int front;//永远指向列头的前一个位置 取数据时后移一位返回即可 之所以要指向前一位是为了方便判断队列是否为空
    int rear;//指向队列尾部 即最后一个数据
    int[] arr;

    public ArrayQueue(int maxSize) {
        this.maxSize = maxSize;
        this.front = -1;
        this.rear = -1;
        this.arr = new int[maxSize];
    }

    public boolean isFull() {
        return rear == maxSize-1;
    }

    public boolean isEmpty() {
        return rear == front;
    }

    //加入队列
    public void add(int n) {
        if (isFull()) {
            System.out.println("队列满了，加不了数据");
            return;
        }
        rear++;
        arr[rear] = n;
    }

    //出队列
    public int getQueue() {
        if (isEmpty()) {
            throw new RuntimeException("队列为空，获取不到数据");
        }
        front++;
        return arr[front];
    }

    public void showQueue() {
        if (isEmpty()) {
            throw new RuntimeException("队列为空，获取不到数据");
        }
        for (int i = 0; i < arr.length; i++) {
            System.out.printf("arr[%d]=%d\n", i, arr[i]);
        }
    }

}

/**
 * 改进成环形数组
 */
class CircleArrayQueue {
    // (1)在队列的尾部元素后预留一个空位，这个空间是动态变化的，由rear指针指向它。数组剩下的元素形成队列元素
    // 预留可以防止当rear < front时队列已满的情况，如果没有预留，那就刚好是rear（尾部元素的下一个） = front，和判断为空的条件冲突
    // front指向队列第一个元素
    // rear指向队列最后一个元素的后一个
    // 数组长度 = maxSize
    // (2)队空条件 front = rear
    // (3)队满条件，条件为rear指针往后移一位刚好等于front指针：（rear + 1）% maxsize = front
        int maxSize;
        int front;
        int rear;
        int[] arr;

        public CircleArrayQueue(int maxSize) {
            this.maxSize = maxSize;
//            this.front = 0;
//            this.rear = 0;
            this.arr = new int[maxSize];
        }

        //队列满：rear指针+1恰好指向头部元素
        //1.如果rear > front，当rear指向数组的最后一个元素时，
        // 即等于maxSize-1，再加1，maxSize % maxSize = 0，如果front = 0那么就是满的
        //2.如果rear < front，后移一位 = front，也可以用这个式子表示。
        public boolean isFull() {
            return (rear + 1) % maxSize == front;
        }

        //队列空：头部元素指向的是尾部元素的下一个
        public boolean isEmpty() {
            return front == rear;
        }

        //加入队列
        public void add(int n) {
            if (isFull()) {
                System.out.println("队列满了，加不了数据");
                return;
            }
            arr[rear] = n;
            rear = (rear + 1) % maxSize;
        }

        //出队列
        public int getQueue() {
            if (isEmpty()) {
                throw new RuntimeException("队列为空，获取不到数据");
            }
            //先保存到临时变量 再返回 否则没有返回机会了
            int val = arr[front];
            front = (front + 1) % maxSize;
            return val;
        }

        public void showQueue() {
            if (isEmpty()) {
                throw new RuntimeException("队列为空，获取不到数据");
            }
            //从front开始遍历，并需要知道队列有多少个元素
            for (int i = front; i < front + size(); i++) {
                System.out.printf("arr[%d]=%d\n", i % maxSize, arr[i % maxSize]);
            }
        }

        public int size() {
            // 如果在rear > front，size = rear - front 也等价于((rear - front) + maxSize) % maxSize
            // 如果rear < front，size = rear + (maxSize - front)，等价于(rear + (maxSize - front)) % maxSize
            return (rear + (maxSize - front)) % maxSize;
        }

}
